package com.train.mgr.modules.biz.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.train.common.model.PageResult;
import com.train.mgr.modules.biz.dto.StatCourseOverviewTraineeDTO;
import com.train.mgr.modules.biz.dto.request.StatQueryDTO;
import com.train.mgr.modules.biz.dto.request.StatViewDTO;
import com.train.mgr.modules.biz.entity.*;
import com.train.mgr.modules.biz.mapper.StatCourseOverviewMapper;
import com.train.mgr.modules.biz.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 课程/课时学习总览统计表 服务实现类
 * </p>
 *
 * @author cxg
 * @date 2025-10-11
 */
@Slf4j
@RequiredArgsConstructor
@Service("IStatCourseOverviewService")
public class StatCourseOverviewServiceImpl extends ServiceImpl<StatCourseOverviewMapper, StatCourseOverview> implements IStatCourseOverviewService {

    private final ICourseService courseService;
    private final ICourseUserService courseUserService;
    private final ILessonUserStudyService lessonUserStudyService;
    private final IStatLessonTraineeService statLessonTraineeService;
    @Override
    public PageResult<StatCourseOverview> courseOverviewList(StatViewDTO params){
        Page<StatCourseOverview> page = params.buildPage();
        LambdaQueryWrapper<StatCourseOverview> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(StatCourseOverview::getCourseId,params.getCourseId());
        queryWrapper.eq(params.getStudyType() != null,StatCourseOverview::getStudyType,params.getStudyType());
        queryWrapper.orderByDesc(StatCourseOverview::getCreateTime);
        Page<StatCourseOverview> resultPage = baseMapper.selectPage(page, queryWrapper);
        return PageResult.of(resultPage, StatCourseOverview.class);
    }

    @Override
    public void buildLessonTraineeStat(String courseId) {
        List<StatCourseOverview> stats = new ArrayList<>();
        UpdateWrapper<StatCourseOverview> updateWrapper = new UpdateWrapper<>();
        updateWrapper.ne(StrUtil.isBlank(courseId),"id", 0L);
        updateWrapper.eq(StrUtil.isNotBlank(courseId),"course_id", courseId);
        baseMapper.delete(updateWrapper);
        List<Course> courseList;
        if (StrUtil.isBlank(courseId)){
            courseList = courseService.getCourseList();
        } else {
            Course course = courseService.getById(courseId);
            courseList = Collections.singletonList(course);
        }
        for (Course course : courseList) {
            LambdaQueryWrapper<CourseUser> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(CourseUser::getCourseId,course.getId())
                            .eq(CourseUser::getIsDeleted,0);
            List<CourseUser> list = courseUserService.list(queryWrapper);
            LambdaQueryWrapper<LessonUserStudy> qw = Wrappers.lambdaQuery();
            queryWrapper.eq(CourseUser::getCourseId,course.getId())
                    .eq(CourseUser::getIsDeleted,0);
            List<LessonUserStudy> studyList = lessonUserStudyService.list(qw);
            LambdaQueryWrapper<StatLessonTrainee> lessonStateQ = Wrappers.lambdaQuery();
            lessonStateQ.eq(StatLessonTrainee::getCourseId,course.getId());
            List<StatLessonTrainee> lessonTraineeList = statLessonTraineeService.list(lessonStateQ);
            int traineeNum = list.size();
            List<StatCourseOverviewTraineeDTO> statCourseOverviewTraineeDTOS = baseMapper.buildCourseOverviewStat(course.getId());
            for (StatCourseOverviewTraineeDTO statCourseOverviewTraineeDTO : statCourseOverviewTraineeDTOS) {
                List<StatLessonTrainee> statLessonTrainees = lessonTraineeList.stream()
                        .filter(lessonTrainee -> lessonTrainee.getLessonId().equals(statCourseOverviewTraineeDTO.getLessonId())
                            && lessonTrainee.getLessonExercisesNum() > 0)
                        .collect(Collectors.toList());
                StatCourseOverview statCourseOverview = new StatCourseOverview();
                statCourseOverview.setCourseId(course.getId());
                statCourseOverview.setStudyName(statCourseOverviewTraineeDTO.getLessonName());
                statCourseOverview.setStudyType(2);
                statCourseOverview.setLessonId(statCourseOverviewTraineeDTO.getLessonId());
                statCourseOverview.setCustomerId(course.getCustomerId());
                statCourseOverview.setTraineeNum(traineeNum);
                long count = studyList.stream().filter(study -> study.getIsFinish().equals(1) && study.getLessonId().equals(statCourseOverviewTraineeDTO.getLessonId())).count();
                statCourseOverview.setFinishNum(String.valueOf(count));
                BigDecimal finish = BigDecimal.valueOf(count).divide(BigDecimal.valueOf(traineeNum), 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
                if (finish.compareTo(BigDecimal.ZERO) == 0){
                    statCourseOverview.setFinishRate("0");
                } else if (finish.compareTo(BigDecimal.valueOf(100)) == 0){
                    statCourseOverview.setFinishRate("100");
                } else {
                    statCourseOverview.setFinishRate(finish.setScale(3, RoundingMode.HALF_UP).toPlainString().replace(".000", ""));
                }
                if (CollUtil.isNotEmpty(statLessonTrainees)){
                    int lessonExercisesNum = statLessonTrainees.stream().map(StatLessonTrainee::getLessonExercisesNum).filter(Objects::nonNull).reduce(0, Integer::sum);
                    statCourseOverview.setPerExercisesNum(BigDecimal.valueOf(lessonExercisesNum).divide(BigDecimal.valueOf(statLessonTrainees.size()),0, RoundingMode.HALF_UP).toPlainString());
                    BigDecimal reduce = statLessonTrainees.stream().map(StatLessonTrainee::getLessonLearnDuration).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
                    statCourseOverview.setPerExercisesDuration(reduce.divide(BigDecimal.valueOf(statLessonTrainees.size()),0, RoundingMode.HALF_UP).intValueExact());
                    BigDecimal lessonOverallScore = statLessonTrainees.stream().map(StatLessonTrainee::getLessonOverallScore).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
                    statCourseOverview.setOverallAvgScore(lessonOverallScore.divide(BigDecimal.valueOf(statLessonTrainees.size()),0, RoundingMode.HALF_UP));
                } else {
                    statCourseOverview.setPerExercisesNum("0");
                    statCourseOverview.setPerExercisesDuration(0);
                    statCourseOverview.setOverallAvgScore(BigDecimal.ZERO);
                }
                stats.add(statCourseOverview);
            }
            // 计算课程
            StatCourseOverview courseOverview = new StatCourseOverview();
            courseOverview.setCourseId(course.getId());
            courseOverview.setStudyName(course.getCourseName());
            courseOverview.setStudyType(1);
            courseOverview.setCustomerId(course.getCustomerId());
            courseOverview.setTraineeNum(traineeNum);
            String finishNum = String.valueOf(list.stream().filter(x -> x.getIsFinish() == 1).count());
            courseOverview.setFinishNum(finishNum);
            if (traineeNum == 0){
                courseOverview.setFinishRate("0");
            } else {
                BigDecimal divide = new BigDecimal(finishNum).divide(BigDecimal.valueOf(traineeNum), 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
                if (divide.compareTo(new BigDecimal(100)) == 0){
                    courseOverview.setFinishRate("100");
                } else {
                    courseOverview.setFinishRate(divide.setScale(3, RoundingMode.HALF_UP).toPlainString());
                }
            }
            List<StatLessonTrainee> statCourseTrainees = lessonTraineeList.stream()
                    .filter(lessonTrainee -> lessonTrainee.getCourseId().equals(course.getId()))
                    .collect(Collectors.toList());
            if (CollUtil.isNotEmpty(statCourseTrainees)){
                long distinctNum = statCourseTrainees.stream().filter(x -> x.getLessonExercisesNum() != null && x.getLessonExercisesNum() > 0).map(StatLessonTrainee::getUsername).distinct().count();
                if (distinctNum == 0){
                    courseOverview.setPerExercisesNum("0");
                    courseOverview.setPerExercisesDuration(0);
                } else {
                    int lessonExercisesNum = statCourseTrainees.stream().map(StatLessonTrainee::getLessonExercisesNum).filter(Objects::nonNull).reduce(0, Integer::sum);
                    courseOverview.setPerExercisesNum(BigDecimal.valueOf(lessonExercisesNum).divide(BigDecimal.valueOf(distinctNum), 0, RoundingMode.HALF_UP).toPlainString());
                    BigDecimal reduce = statCourseTrainees.stream().map(StatLessonTrainee::getLessonLearnDuration).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
                    courseOverview.setPerExercisesDuration(reduce.divide(BigDecimal.valueOf(distinctNum), 0, RoundingMode.HALF_UP).intValueExact());
                    BigDecimal lessonOverallScore = statCourseTrainees.stream().map(StatLessonTrainee::getLessonOverallScore).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);

                    long count = statCourseTrainees.stream().filter(x -> x.getLessonExercisesNum() != null && x.getLessonExercisesNum() > 0).count();
                    if (count == 0) {
                        courseOverview.setOverallAvgScore(BigDecimal.ZERO);
                    } else {
                        courseOverview.setOverallAvgScore(lessonOverallScore.divide(BigDecimal.valueOf(count), 0, RoundingMode.HALF_UP));
                    }
                }
            } else {
                courseOverview.setPerExercisesNum("0");
                courseOverview.setPerExercisesDuration(0);
                courseOverview.setOverallAvgScore(BigDecimal.ZERO);
            }
            stats.add(courseOverview);
        }
        if (stats.size() > 0){
            saveBatch(stats);
        }
    }


}
